package com.cymal.condition.component;


import com.cymal.condition.Condition;
import com.cymal.entity.po.subject.AbstractSubject;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 与条件
 * @param <Subject> 题目
 * @param <Req> 请求
 */
public class AndCondition<Subject extends AbstractSubject, Req> implements Condition<Subject, Req> {


    /**
     * 题目
     */
    private final Subject subject;


    /**
     * 子条件
     */
    private final List<Condition<Subject ,Req>> childs;


    /**
     * Constructor.
     * @param conditions 子条件
     */
    public AndCondition(Subject subject ,Condition<Subject ,Req> ... conditions) {
        if (Objects.isNull(subject)) {
            throw new NullPointerException("subject must not be null.");
        }
        if (Objects.isNull(conditions)) {
            throw new NullPointerException("children must not be null.");
        }
        if (conditions.length < 2) {
            throw new IllegalArgumentException("child length must >= 2.");
        }
        List<Condition<Subject ,Req>> list = new ArrayList<>();
        for(Condition condition : conditions) {
            if (Objects.isNull(condition)) {
                throw new NullPointerException("child must not be null.");
            }
            if (condition instanceof AndCondition) {
                list.addAll(((AndCondition<Subject ,Req>) condition).childs);
            } else {
                list.add(condition);
            }
        }
        this.subject = subject;
        this.childs = Collections.unmodifiableList(list);
    }


    /**
     * Construtor.
     * @param subject 题目
     * @param conditions 条件
     */
    public AndCondition(Subject subject ,Collection<Req> conditions) {
        this(subject ,CollectionUtils.isEmpty(conditions) ? null : conditions.toArray(new Condition[conditions.size()]));
    }


    /**
     * 匹配.
     * @param subject 题目
     * @param requests 请求.
     * @return ture or false.
     */
    @Override
    public Boolean matched(Subject subject ,Req... requests) {
        Optional<Boolean> result = this.childs.stream()
                .map(child -> child.matched(subject ,requests))
                .filter(BooleanUtils::isFalse)
                .findFirst();
        return result.orElse(Boolean.TRUE);
    }

    @Override
    public Boolean matched(Subject subject, Collection<Req> requests) {
        return null;
    }


    /**
     * 逻辑条件没有类型
     * @return null
     */
    @Override
    public AbstractSubject.SubjectType conditionType() {
        return null;
    }


}
